
<!-- 自定义组件 -->
<template>
    <el-card class="box-card">
        <div class="model-role">
            <!-- 搜索栏 表单组件 -->
            <el-form :inline="true" :model="formData" class="demo-form-inline">
                <el-form-item label="角色名称">
                    <el-input v-model="formData.roleName" placeholder="角色名称" clearable>
                    </el-input>
                </el-form-item>
                <el-form-item>
                    <el-button @click="getDataList(1)">查询</el-button>
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" @click="openDialog">新增</el-button>
                </el-form-item>
            </el-form>
            <!-- 表格组件 -->
            <el-table :data="tableData" border style="width: 100%">
                <el-table-column type="selection" width="55"></el-table-column>
                <el-table-column prop="roleId" label="ID" width="150"></el-table-column>
                <el-table-column prop="roleName" label="角色名称" width="180"> </el-table-column>
                <el-table-column prop="remark" label="备注" width="280"> </el-table-column>
                <el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
                <el-table-column label="操作">
                    <!-- 通过slot-scope="scope" 来获取当前行的索引 以及 行数据row -->
                    <template slot-scope="scope" width="180">
                        <el-button size="mini" type="primary" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
                        <el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button>
                    </template>
                </el-table-column>
            </el-table>
            <!-- 分页组件 -->
            <el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" :current-page="pageIndex"
                :page-sizes="[5, 10, 20, 50, 100]" :page-size="pageSize" :total="totalCount"
                layout="total, sizes, prev, pager, next, jumper" style="margin-top:30px;">
            </el-pagination>
        </div>
        <!-- dialog对话框 包含表单 -->
        <!-- '新增角色' '编辑角色' 共用一个对话框，但是yh觉得分开各自一个对话框比较好，避免一些显示混乱，耦合度低一些 -->
        <!-- 解释：:close-on-click-modal="false" 默认点击对话框周围会关闭对话框，此属性是不允许点击周围来关闭对话框 -->
        <el-dialog :title="dialogForm.roleId == null ? '新增角色' : '编辑角色'" :visible.sync="dialogFormVisible" width="35%"
            :close-on-click-modal="false" @closed="closeDialog">
            <!-- 表单添加校验规则： 
                    1、<el-form>中添加属性:rules="rules" 
                    2、在data()数定义rules：{}规则
                    3、输入框所在的<el-form-item>中添加属性prop="roleName",与rules：{roleName：[]}规则中的属性名roleName一致
                    4、<el-form>中添加属性ref="dialogForm" 
                    5、在提交方法中使用this.$refs["dialogForm"].validate()使校验生效
                    注意：前三步完成可以使输入框提示校验信息，但是不能阻拦提交函数的执行。需要4,5步才可以。
                     -->
            <el-form :model="dialogForm" :rules="rules" ref="dialogForm">
                <el-form-item label="角色名称" prop="roleName" label-width="90px">
                    <el-input v-model="dialogForm.roleName" placeholder="角色名称" autocomplete="off"></el-input>
                </el-form-item>
                <el-form-item label="备注信息" prop="remark" label-width="90px">
                    <el-input type="textarea" v-model="dialogForm.remark" placeholder="备注信息" autocomplete="off"></el-input>
                </el-form-item>
                <el-form-item label="菜单分配" prop="remark" label-width="90px">
                    <el-tree :data="menuTreeData.menus" show-checkbox node-key="id"
                        :props="elTreeProps" ref="menuTree"> 
                        <!--  :default-checked-keys="menuTreeData.roleAuthedMenuIds" 不需要了，在js中动态指定被选中的节点 -->
                    </el-tree>
                </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
                <el-button @click="dialogFormVisible = false">取 消</el-button>
                <el-button type="primary" @click="submitDialog">确 定</el-button>
            </div>
        </el-dialog>
    </el-card>
</template>

<script>
export default {
    name: 'sysRole',
    data() {
        /**
         * 自定义表单校验, 验证角色名称不可重复
         * @param {*} rule  规则对象
         * @param {*} value  输入的值
         * @param {*} callback  回调函数，方法出口
         */
        var repeatRoleName = (rule, value, callback) => {
            //是否有其他的和当前角色名一样的角色数据
            if (value === '') {
                callback(new Error('角色名称为必填项'));
            } else {
                //查询其他角色是否已经有重复的名称:是否存在角色名称，但不是当前的角色
                this.$http.post("/sys/sysRole/existRoleName", this.dialogForm).then((res) => {
                    //console.log("查询是否存在角色名称：", res);
                    if (res.data.data === true) {
                        //console.log("能进来")
                        callback(new Error('角色名称已经存在，请换一个试试'));
                    } else {
                        callback();
                    }
                }).catch(function (error) {
                    console.log(error);
                })
            }
        };
        return {
            //查询的 表单数据
            formData: {
                roleName: ""
            },
            //表格数据
            tableData: [],
            pageIndex: 1,
            pageSize: 5,
            totalCount: 0,//总条数
            dataListLoading: false, //表格数据查询处理中，避免频繁重复点击
            /** dialog对话框 */
            dialogFormVisible: false, //dialog对话框打开状态
            dialogForm: {  //对话框表单数据
                roleId: null,  // 给个默认值，为了后续好判断
                roleName: "",
                remark: "",
                menuIds: [] //保存的角色关联的菜单
            },
            submitAddLoading: false,//提交处理中，避免频繁重复点击
            // formLabelWidth: "70px" //label的宽度（输入框前面的中文）
            //菜单分配使用的树形菜单数据
            menuTreeData: {},
            //props属性
            elTreeProps: {
                label: 'name', //指定节点标签为节点对象的某个属性值  string, function(data, node)
                children: 'children' //指定子树为节点对象的某个属性值  string
            },
            //表单校验规则
            rules: {
                roleName: [
                    //  trigger校验时机： blur：失去焦点
                    // { required: true, message: '请输入角色名称', trigger: 'blur' } //表单校验原生方式
                    { validator: repeatRoleName, trigger: 'blur' } //自定义表单校验方式 需要定义一个变量repeatRoleNma 
                ],
                remark: [
                    { required: true, message: '请输入备注信息', trigger: 'blur' }
                ]
            }
        }
    },
    methods: {
        //查询事件
        getDataList(pageIndex) {
            /** 校验 重复操作 之后可以使用loading层解决*/
            if (this.dataListLoading) {
                //如果正在处理查询，则忽略本次点击
                return;
            }
            this.dataListLoading = true; //查询处理中
            /** 解决 页码虚高的问题  */
            //如果是点击查询按钮进来的，则从第一页开始查询，解决问题：之前查询了第n页数据，但是新输入的条件没有那么多数据，造成点击查询后显示第n页无数据的问题
            if (pageIndex) {
                this.pageIndex = pageIndex;
            }
            //声明params查询的参数
            const params = {
                pageIndex: this.pageIndex,
                pageSize: this.pageSize,
                roleName: this.formData.roleName
            };
            //debugger;
            //请求查询角色列表数据
            this.$http.get("/sys/sysRole/list", { params: params }).then((res) => {
                //console.log("查询角色,服务返回", res);
                this.tableData = res.data.data.list;  //表格数据
                this.totalCount = res.data.data.totalCount;  //总条数
            }).catch(function (error) {
                console.log(error);
            })
            this.dataListLoading = false; //查询处理结束
        },
        // 分页-切换页容量
        sizeChangeHandle(pageSize) {
            this.pageSize = pageSize; //切换 pageSize
            this.pageIndex = 1; //切换size后跳转到第一页
            this.getDataList(); //刷新表格数据
        },
        // 分页-跳转指定页码
        currentChangeHandle(pageIndex) {
            this.pageIndex = pageIndex; //跳转到指定页
            this.getDataList(); //刷新表格数据
        },
        //添加 角色数据 对话框
        openDialog() {
            //查询所有菜单树的数据
            this.$http.get("/sys/sysRole/dispatcherRoleMenu").then((res) => {
                console.log("dispatcherRoleMenu服务返回", res);
                this.menuTreeData = res.data.data;
                this.dialogFormVisible = true; //打开对话框
            }).catch(function (error) {
                console.log(error);
            })
        },
        //提交对话框 添加/编辑角色数据
        submitDialog() {
            //获取对应表单并校验通过才可以提交，否则无法提交
            this.$refs["dialogForm"].validate((valid) => {
                if (valid) {
                    //处理中，直接忽略点击事件，避免重复点击
                    if (this.submitAddLoading) {
                        return;
                    }
                    this.submitAddLoading = true; //开始处理
                    //执行提交请求
                    this.doSubmitAdd();
                    this.submitAddLoading = false; //结束处理
                } else {
                    console.log('error submit!!');
                    return false;
                }
            });
        },
        //真正校验表单后的提交
        doSubmitAdd() {
            // 将树形结构中选择的菜单ID(包含半选择的菜单id)绑定到表单的提交数据中。
            this.dialogForm.menuIds = this.getMenuAllCheckedKeys();
            //alert(this.dialogForm.menuIds);
            //请求后台提交数据
            this.$http.post("/sys/sysRole/save", this.dialogForm).then((res) => {
                //console.log("保存角色,服务返回", res);
                this.dialogFormVisible = false; //关闭对话框
                this.getDataList(); //刷新表格当前页数据
            }).catch(function (error) {
                console.log(error);
            })
        },
        // 获得所有选中的菜单节点数据，包含半选中的节点
        getMenuAllCheckedKeys() {
            // 目前被选中的菜单节点
            let checkedKeys = this.$refs.menuTree.getCheckedKeys();
            // 半选中的菜单节点
            let halfCheckedKeys = this.$refs.menuTree.getHalfCheckedKeys();
            //unshift函数是JavaScript 中用于向一个数组的开头添加一个或多个元素的函数。这个函数会改变原数组，返回值为数组的新长度
            checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
            return checkedKeys;
        },
        //打开编辑 角色数据
        handleEdit(index, row) {
            //alert(row.roleId)
            //查询所有菜单树的数据+角色关联的菜单ids
            this.$http.get("/sys/sysRole/dispatcherRoleMenu?roleId=" + row.roleId).then((res) => {
                //console.log("dispatcherRoleMenu服务返回", res);
                //把响应结果里所有的menuId属性名换成id
                this.menuTreeData = JSON.parse(JSON.stringify(res.data.data).replace(/"menuId"/g, '"id"'));
                this.menuTreeData.roleAuthedMenuIds.forEach((id) => {
                this.$nextTick(() => {
                    var node = this.$refs.menuTree.getNode(id);
                    // isLeaf为tree组件自带属性，用于判断当前节点是否为子节点
                    if (node.isLeaf) {
                    // 只选中子节点，父节点自动为半选中状态
                    this.$refs.menuTree.setChecked(node, true);
                    }
                });
                });


            }).catch(function (error) {
                console.log(error);
            })
            this.dialogFormVisible = true; //打开对话框
            // 回显对话框表单里的数据
            this.dialogForm = {
                roleId: row.roleId,
                roleName: row.roleName,
                remark: row.remark
            };
        },
        submitEdit() {
            //编辑与添加使用了同一套对话框，提交函数也使用了添加的提交。
            //这里为了演示方便，没有分成两套对话框，实际使用分开更容易辨别，避免坑
        },
        //删除角色数据
        handleDelete(index, row) {
            this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning'
            }).then(() => {
                //GET this.$http.get("/sys/sysRole/deleteById?roleId=" + row.roleId
                //POST axios 的 Content-Type: multipart/form-data 方式提交
                let params = new FormData();
                params.append('roleId', row.roleId);
                this.$http.post("/sys/sysRole/deleteById", params
                ).then((res) => {
                    console.log("删除角色,服务返回", res);
                    if (res.data.data === true) {
                        this.$message({
                            type: 'success',
                            message: '删除成功!'
                        });
                    } else {
                        this.$message({
                            type: 'warning',
                            message: '该数据不可被删除！！'
                        });
                    }
                    this.getDataList();//刷新表格当前页数据
                }).catch(function (error) {
                    console.log(error);
                });
            }).catch(() => {
                this.$message({
                    type: 'info',
                    message: '已取消删除'
                });
            });

        },
        //监听对话框关闭after事件
        closeDialog() {
            //console.log("监听关闭对话框，清除数据")
            //清除对话框表单中的数据
            this.dialogForm = {
                roleId: null,
                roleName: "",
                remark: ""
            };
        }

    },
    // mounted在模板渲染成html后调用
    mounted() {
        //打开页面自动查询系统角色数据
        this.getDataList();
    }
}
</script>